<template>
	<view :style="{background: bgColor}">
		<scroll-view :scroll-x="scrollX" :scroll-y="!scrollX" scroll-with-animation>
			<view class="tabs" :class="{row:scrollX}">
				<view class="tab-item" v-for="(item,index) in list" :key="item.id" @tap="changeHandle(index)" :style="[tabItemStyle(index)]">
					{{item[valueName]? item[valueName]:item}}
				</view>
				<view v-if="showBar" class="tab-bar" :style="[tabBarStyle]"></view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
	export default {
		props: {
			// 需循环的标签列表
			list: {
				type: Array,
				default: () => []
			},
			// 当前活动tab的索引
			current: {
				type: Number,
				default: 0
			},
			// 导航栏的背景颜色
			bgColor: {
				type: String,
				default: '#ffffff'
			},
			// 导航栏的高度和行高
			height: {
				type: [String, Number],
				default: 44
			},
			// 字体大小
			fontSize: {
				type: [String, Number],
				default: 14
			},
			// 过渡动画时长, 单位ms
			duration: {
				type: [String, Number],
				default: 0.5
			},
			// 选中项的主题颜色
			activeColor: {
				type: String,
				default: '#2979ff'
			},
			// 未选中项的颜色
			inactiveColor: {
				type: String,
				default: '#666'
			},
			// 标签的宽度
			itemWidth: {
				type: [Number, String],
				default: 'auto'
			},
			// 单个tab的内边距
			gutter: {
				type: [String, Number],
				default: 14
			},
			// 是否显示底部的滑块
			showBar: {
				type: Boolean,
				default: true
			},
			// 菜单底部移动的bar的宽度，单位px
			barWidth: {
				type: [String, Number],
				default: 44
			},
			// 移动bar的高度
			barHeight: {
				type: [String, Number],
				default: 3
			},
			// item的样式
			itemStyle: {
				type: Object,
				default () {
					return {}
				}
			},
			// 当前活动tab item的样式
			activeItemStyle: {
				type: Object,
				default () {
					return {}
				}
			},
			// 排列方向 row-横向，col-竖向
			direction: {
				type: String,
				default: 'row'
			},
			// 显示的属性名
			valueName: {
				type: String,
				default: 'name'
			},
		},
		data() {
			return {
				parentLeft: 0, // tabs组件距离屏幕左边的宽度
				parentTop: 0, // tabs组件距离屏幕顶部的高度
				componentWidth: 0, // tabs组件的宽度
				tabQueryInfo: [], // 存放对tab菜单查询后的节点信息
				scrollBarLeft: 0, // 移动bar需要通过translateX()移动的距离
				scrollBarTop: 0, // 移动bar需要通过translateY()移动的距离
				currentIndex: this.current,
				barFirstTimeMove: true, // 滑块第一次移动时(页面刚生成时)，无需动画，否则给人怪异的感觉
				scrollX: this.direction === 'row',
				// scrollY: false,
			}
		},
		computed: {
			// 移动bar的样式
			tabBarStyle() {
				let style = {
					width: this.barWidth + 'px',
					transform: `translate(${this.scrollBarLeft}px, ${this.scrollBarTop}px)`,
					// 滑块在页面渲染后第一次滑动时，无需动画效果
					'transition-duration': `${this.barFirstTimeMove ? 0 : this.duration }s`,
					'background-color': this.activeColor,
					height: this.barHeight + 'px',
					// 设置一个很大的值，它会自动取能用的最大值，不用高度的一半，是因为高度可能是单数，会有小数出现
					'border-radius': `${this.barHeight / 2}px`
				};
				Object.assign(style, this.barStyle);
				return style;
			},
			// tab的样式
			tabItemStyle() {
				return (index) => {
					let style = {
						height: this.height + 'px',
						'line-height': this.height + 'px',
						'font-size': this.fontSize + 'px',
						'transition-duration': `${this.duration}s`,
						color: index == this.currentIndex ? this.activeColor : this.inactiveColor,
						width: this.itemWidth + 'px',
						'margin-left': this.direction === 'col' || index === 0 ? 0 : `${this.gutter}px`,
					};

					style = Object.assign(style, this.itemStyle);

					if (index == this.currentIndex) {
						style = Object.assign(style, this.activeItemStyle);
					}
					return style;
				}
			},
		},
		watch: {
			current: {
				immediate: true,
				handler(nVal, oVal) {
					// 视图更新后再执行移动操作
					this.$nextTick(() => {
						this.currentIndex = nVal;
						this.scrollBarByIndex();
					});
				}
			},
		},
		mounted() {
			this.init()
		},
		methods: {
			init() {
				const _this = this;
				this.$nextTick(function() {
					let query = uni.createSelectorQuery().in(_this);
					query.select('.tabs').fields({
							size: true,
							rect: true
						})
						// 历遍所有tab，这里是执行了查询，最终使用exec()会一次性返回查询的数组结果
						// 只要size和rect两个参数
						.selectAll('.tab-item').fields({
							size: true,
							rect: true
						})
						// 执行查询，一次性获取多个结果
						.exec(
							function(res) {
								// tabs组件距离屏幕左边的宽度
								_this.parentLeft = !res[0] ? 0 : res[0].left
								_this.parentTop = !res[0] ? 0 : res[0].top
								// tabs组件的宽度
								_this.componentWidth = !res[0] ? 0 : res[0].width
								_this.tabQueryInfo = res[1];
								// 初始化滚动条和移动bar的位置
								_this.scrollBarByIndex();
							}.bind(_this)
						);
				});
			},
			changeHandle(index) {
				if (index === this.currentIndex) return;
				this.$emit('change', index)
			},
			// 移动bar的位置
			scrollBarByIndex() {
				// 取出当前选中的tab信息
				let tabInfo = this.tabQueryInfo[this.currentIndex]
				if (!tabInfo) return;
				let tabWidth = tabInfo.width
				let tabHeight = tabInfo.height
				let tabOffsetLeft = tabInfo.left - this.parentLeft
				let tabOffsetTop = tabInfo.top - this.parentTop

				this.scrollBarLeft = tabOffsetLeft + tabWidth / 2 - this.barWidth / 2
				this.scrollBarTop = tabOffsetTop + tabHeight - this.barHeight
				// 延时是因为scrollBarLeft作用于computed计算时，需要一个过程需，否则导致出错
				if (this.barFirstTimeMove) {
					setTimeout(() => {
						this.barFirstTimeMove = false;
					}, 100)
				}
			},
		}
	}
</script>

<style lang="scss" scoped>
	.tabs {
		position: relative;
		white-space: nowrap;

		.tab-item {
			text-align: center;
		}

		.tab-bar {
			position: absolute;
			top: 0;
		}
	}

	.row {
		display: flex;
		justify-content: flex-start;
		align-items: center;
	}

	.col {
		display: flex;
		flex-direction: column;
	}
</style>
